/* clock_init.c */
#include "clock_init.h"

#include "hal_common.h"
#include "hal_scu.h"
#include "hal_ipc.h"

void BOARD_ResetToDefault(void);

typedef struct
{
    IPC_Periph_Type periph;
    IPC_PeriphFunClkSrc_Type func_clk_src;
    IPC_PeriphFunClkDiv_Type func_clk_div;
} clock_init_conf_t;

const clock_init_conf_t clock_init_conf_arr[] =
{
    { IPC_Periph_PCTRLA, IPC_PeriphFunClkSrc_NONE, IPC_PeriphFunClkDiv_NONE }, /* porta. */
    { IPC_Periph_PCTRLB, IPC_PeriphFunClkSrc_NONE, IPC_PeriphFunClkDiv_NONE }, /* portb. */
    { IPC_Periph_PCTRLC, IPC_PeriphFunClkSrc_NONE, IPC_PeriphFunClkDiv_NONE }, /* portc. */
    { IPC_Periph_PCTRLD, IPC_PeriphFunClkSrc_NONE, IPC_PeriphFunClkDiv_NONE }, /* portd. */
    { IPC_Periph_GPIO  , IPC_PeriphFunClkSrc_NONE, IPC_PeriphFunClkDiv_NONE }, /* gpio. */
    { IPC_Periph_UART0 , IPC_PeriphFunClkSrc_FIRC, IPC_PeriphFunClkDiv_1    }, /* uart0, firc. */
    { IPC_Periph_UART1 , IPC_PeriphFunClkSrc_FIRC, IPC_PeriphFunClkDiv_1    }, /* uart1, firc. */
    { IPC_Periph_eTMR0 , IPC_PeriphFunClkSrc_NONE, IPC_PeriphFunClkDiv_NONE }, /* etmr0, fast_bus_clk. */
    { IPC_Periph_eTMR1 , IPC_PeriphFunClkSrc_NONE, IPC_PeriphFunClkDiv_NONE }, /* etmr0, fast_bus_clk. */
    { IPC_Periph_SPI2  , IPC_PeriphFunClkSrc_FIRC, IPC_PeriphFunClkDiv_4    }, /* spi2, firc/4, 12mhz.*/
    { IPC_Periph_DMA   , IPC_PeriphFunClkSrc_NONE, IPC_PeriphFunClkDiv_NONE }, /* dma. */
    { IPC_Periph_lpTMR0, IPC_PeriphFunClkSrc_SIRC, IPC_PeriphFunClkDiv_4    }, /* lptmr0, sirc, 2mhz. */
    { IPC_Periph_ADC0  , IPC_PeriphFunClkSrc_FIRC, IPC_PeriphFunClkDiv_4    }, /* adc0. firc/4, 12mhz.*/
};

void BOARD_InitBootClocks(void)
{
    /* setup the clock tree. */
    BOARD_ResetToDefault();

    /* enable the clocks to peripherals. */
    for (uint32_t i = 0u; i < (sizeof(clock_init_conf_arr)/sizeof(clock_init_conf_arr[0])); i++)
    {
        IPC_ResetPeriph(IPC,  clock_init_conf_arr[i].periph);
        IPC_EnablePeriph(IPC, clock_init_conf_arr[i].periph,
                              clock_init_conf_arr[i].func_clk_src,
                              clock_init_conf_arr[i].func_clk_div);
    }
#if 0
    /* porta. */
    IPC_ResetPeriph(IPC, IPC_Periph_PCTRLA);
    IPC_EnablePeriph(IPC, IPC_Periph_PCTRLA, IPC_PeriphFunClkSrc_NONE, IPC_PeriphFunClkDiv_NONE);

    /* portb. */
    IPC_ResetPeriph(IPC, IPC_Periph_PCTRLB);
    IPC_EnablePeriph(IPC, IPC_Periph_PCTRLB, IPC_PeriphFunClkSrc_NONE, IPC_PeriphFunClkDiv_NONE);    
    
    /* portc. */
    IPC_ResetPeriph(IPC, IPC_Periph_PCTRLC);
    IPC_EnablePeriph(IPC, IPC_Periph_PCTRLC, IPC_PeriphFunClkSrc_NONE, IPC_PeriphFunClkDiv_NONE);
    
    /* gpio. */
    IPC_ResetPeriph(IPC, IPC_Periph_GPIO);
    IPC_EnablePeriph(IPC, IPC_Periph_GPIO, IPC_PeriphFunClkSrc_NONE, IPC_PeriphFunClkDiv_NONE);

    /* uart0. */
    IPC_ResetPeriph(IPC, IPC_Periph_UART0);
    IPC_EnablePeriph(IPC, IPC_Periph_UART0, IPC_PeriphFunClkSrc_FIRC, IPC_PeriphFunClkDiv_1);
    
    /* uart1. */
    IPC_ResetPeriph(IPC, IPC_Periph_UART1);
    IPC_EnablePeriph(IPC, IPC_Periph_UART1, IPC_PeriphFunClkSrc_FIRC, IPC_PeriphFunClkDiv_1);
#endif
}

/* firc 48mhz as main clk.
 * fast_bus_clk div=1.
 * slow_bus_clk div=2.
 */
void BOARD_ResetToDefault(void)
{
    /* disable all the CMU before any setting up to clock system. */
    SCU->CMU_CTRL = 0;
    SCU->CMUSTS = SCU->CMUSTS; /* clear flags. */

    /* switch the bus clock to sirc. */
    SCU_FircConf_Type firc_conf;
    firc_conf.EnableOnDeepsleepMode = true;
    SCU_SetFircConf(SCU, &firc_conf); /* enable the firc. */
    
    /* use the firc as system clock. */
    SCU_SetSysClkSrcMux(SCU, SCU_ClkSrc_FIRC);
    while (SCU_ClkSrc_FIRC != SCU_GetSysClkSrcMux(SCU))
    {
    }
}

/* EOF. */

